package com.hoshino.momochi.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableList;
import com.hoshino.momochi.annotation.IgnoreLogin;
import com.hoshino.momochi.annotation.LimitCount;
import com.hoshino.momochi.annotation.MaintainToken;
import com.hoshino.momochi.config.Trie.Trie;
import com.hoshino.momochi.mapper.*;
import com.hoshino.momochi.model.DTO.*;
import com.hoshino.momochi.model.domain.*;
import com.hoshino.momochi.service.*;
import com.hoshino.momochi.util.JsonResponse;
import com.hoshino.momochi.util.LuaScript;
import com.hoshino.momochi.util.SHA256;
import com.hoshino.momochi.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.http.MediaType;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class TestController {

    @Autowired
    public StudentService studentService;

    @Autowired
    public AdminService adminService;

    private final RedisTemplate<String, Serializable> limitRedisTemplate;

    private final StringRedisTemplate stringRedisTemplate;


    @Autowired
    public TestController(RedisTemplate<String, Serializable> limitRedisTemplate, StringRedisTemplate stringRedisTemplate) {
        this.limitRedisTemplate = limitRedisTemplate;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    //
    @RequestMapping("student/test")
    @IgnoreLogin
    public JsonResponse getAdminByStudentId(Long id) {
        Student student = studentService.MygetAdminByStudentId(id);
        return JsonResponse.success(student);
    }

    @RequestMapping("admin/test")
    public JsonResponse getStudentListByAdminId(Long id) {
        Admin admin = adminService.getStudentListByAdminId(id);
        return JsonResponse.success(admin);
    }

    @RequestMapping("/test")
    @LimitCount(key = "login", name = "登录接口", prefix = "limit")
    @IgnoreLogin
    public JsonResponse Test(@RequestBody LoginDTO loginDTO, HttpServletRequest request) {
        String hoshino_t_kk = request.getHeader("HOSHINO_T_KK");
        System.out.println(hoshino_t_kk == null || hoshino_t_kk.equals(""));
        log.info("获取header TOKEN {}", hoshino_t_kk);
        return JsonResponse.success("TAKANASHI_HOSHINO");
    }

    /**
     * <p>测试MaintainTokenAspect切面方法</p>
     * <p>作用于登录之后，将生成的Token，与MYSQL中用户ID，存入Redis当中</p>
     *
     * @param request
     * @return
     */
    @RequestMapping("test/tosettoken")
    @IgnoreLogin
    @MaintainToken
    public JsonResponse TestSetToken(HttpServletRequest request) {
        // 通过 用户登录信息 访问数据库获取 用户 id
        Long id = 1L;

        // test Token
        String username = "HOSHINO";

        // 将id 放入request 给 @After MaintainTokenAspect
        request.setAttribute("USER_ID", id);

        String token = TokenUtil.genAccessToken(username);

        // 将 token 放入 request 给 setToekn
        request.setAttribute("HOSHINO_T_KK", token);

        log.info("testtoken, token:{},id:{}", token, id);

        TokenIdDTO res = new TokenIdDTO(token, id);

        return JsonResponse.success(res);
    }

    /**
     * 测试登录拦截器
     *
     * @param request
     * @return
     */
    @RequestMapping("test/interceptor")
    public JsonResponse expireToken(HttpServletRequest request) {
        // 测试 拦截器 token校验
        return JsonResponse.success("test success");
    }

    /**
     * 缓存数据
     *
     * @param request
     * @return
     */
    @RequestMapping("test/loadpage")
    @IgnoreLogin
    public JsonResponse testLoadPage(HttpServletRequest request) {
        // 测试加载页面 数据
        // 一次性获取数据， 然后将获取数据分页存储到 Redis中

        List<testCacheDTO> userlist = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            testCacheDTO item = new testCacheDTO("HOSHINO", 10L);
            userlist.add(item);
        }

        // 分页操作 与 lua 中进行
        // 长度 每页 8 个 上取整
        int page_info = 8;

        int list_len = userlist.size();
        // 页数
        int pages = (list_len + page_info - 1) / page_info;

        // 分页过后 每页 的 JSON 字符串
        List<String> Ans = new ArrayList<>();

        for (int i = 0; i < pages; i++) {
            Ans.add(JSON.toJSONString(userlist.stream().skip(i * page_info).limit(page_info).toList()));
        }

        // KEYS
//        ImmutableList<String> front = ImmutableList.of(StringUtils.join("cache" + "_", "page", "_"));
        String front = "cache_page_";
        String luaScript = LuaScript.doCacheFrontScript(front);
        RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);

        // 执行 lua 脚本
        Number count = stringRedisTemplate.execute(redisScript, Ans, StringUtils.join(pages), front); // keys ARGV...

//        System.out.println(Ans.get(0));

//        String jsons = JSON.toJSONString(userlist);
//        // KEYS
//        ImmutableList<String> keys = ImmutableList.of(StringUtils.join("datasets" + "_", "1", "3"));
//        String luaScript = setListJson();
//        RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
//
//        // 执行 lua 脚本
//        Number count = limitRedisTemplate.execute(redisScript, keys, userlist); // keys ARGV...
        return JsonResponse.success("dd");
    }

    /**
     * 读取缓存数据
     *
     * @param request
     * @return
     */
    @RequestMapping("test/loadcache")
    @IgnoreLogin
    public JsonResponse loadCache(HttpServletRequest request) {
        // 首先 需要 页码
        int need_page = 2;
        // 接着 需要 key 前缀
        String front = "cache_page_";

        // redis
        ImmutableList<String> keys = ImmutableList.of(StringUtils.join(front, need_page));
        String luaScript = LuaScript.getCacheScript();
        RedisScript<String> redisScript = new DefaultRedisScript<>(luaScript, String.class);

        // 执行 lua 脚本
        String count = stringRedisTemplate.execute(redisScript, keys); // keys ARGV...

//        List<String> Ans = JSON.parseArray(count, String.class);
//        log.info("获取当前页面数据为:{}", Ans);
        System.out.println(count);

        List<testCacheDTO> Ans = JSON.parseArray(count, testCacheDTO.class);

        System.out.println(Ans);

        return JsonResponse.success("");
    }

    @Autowired
    private SseService sseService;

    /**
     * 测试 sse 连接
     *
     * @return
     */
    @RequestMapping(value = "test/sseconnect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter sse(HttpServletRequest request) {
//        String token = TokenUtil.genAccessToken("HOSHINO");
//        String token1 = request.getHeader("HOSHINO_T_KK");
//        System.out.println(token1);
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IkhPU0hJTk8iLCJqdGkiOiIyYTgzOGNiNC01ZjRmLTRlYWYtYTdjOC02ZTg0ZDZiNTkwNGIiLCJleHAiOjE3MjAwMjE5ODUsImlhdCI6MTcyMDAyMDc4NSwic3ViIjoiUGVyaXBoZXJhbHMiLCJpc3MiOiJIT1NISU5PIn0.d9bLXgYfvIwL8n0yGLT2rTKqmUUvRV79b1Vw2IPzcd8";
        Long userId = (Long) request.getAttribute("USER_ID");
        log.info("token:{}", userId);
        return sseService.connect(1L);
    }

    /**
     * 测试 sse 消息发送
     */
    @RequestMapping("test/ssesend")
    @IgnoreLogin
    public void sendMessage() {
//        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IkhPU0hJTk8iLCJqdGkiOiIyYTgzOGNiNC01ZjRmLTRlYWYtYTdjOC02ZTg0ZDZiNTkwNGIiLCJleHAiOjE3MjAwMjE5ODUsImlhdCI6MTcyMDAyMDc4NSwic3ViIjoiUGVyaXBoZXJhbHMiLCJpc3MiOiJIT1NISU5PIn0.d9bLXgYfvIwL8n0yGLT2rTKqmUUvRV79b1Vw2IPzcd8";
        testCacheDTO t = new testCacheDTO("HOSHINO", 18L);

//        sseService.sendMessage(1L, JSON.toJSONString(t));

    }

    /**
     * 测试多用户连接 广播消息
     *
     * @param
     * @return
     */
    @RequestMapping("test/userconnect")
    @IgnoreLogin
    public SseEmitter userConnect() {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IkhPU0hJTk8iLCJqdGkiOiIyYTgzOGNiNC01ZjRmLTRlYWYtYTdjOC02ZTg0ZDZiNTkwNGIiLCJleHAiOjE3MjAwMjE5ODUsImlhdCI6MTcyMDAyMDc4NSwic3ViIjoiUGVyaXBoZXJhbHMiLCJpc3MiOiJIT1NISU5PIn0.d9bLXgYfvIwL8n0yGLT2rTKqmUUvRV79b1Vw2IPzcd8";
        return sseService.connect(1L);
    }

    /**
     * 测试消息广播
     *
     * @param request
     */
    @RequestMapping("test/message")
    @IgnoreLogin
    public JsonResponse redioMessage(HttpServletRequest request, @RequestBody MessageDTO message) {
        // 首先 需要从 MYSQL 中 获取 当前用户的 被关注列表 用户ID
        List<Long> concernList = new ArrayList<>();
        // 假设 ID = 1 的用户 发送给 ID = 2 的用户
        concernList.add(2L);

        // 然后循环 发送消息
        for (var i : concernList) {
            //....
            boolean r = sseService.sendMessage(1L, i, message.getMessage());
            if (r == true) {
                // 正常发送
            } else {
                // 用户离线
                // 将该对象存入 redis
                MessageDTO messageDTO = new MessageDTO(message.getSend_id(), i, message.getMessage());
                log.info("将消息存入Redis");
                // redis
                ImmutableList<String> keys = ImmutableList.of(StringUtils.join("message_", 2));
                String luaScript = LuaScript.saveMessageScript();
                RedisScript<Void> redisScript = new DefaultRedisScript<>(luaScript, Void.class);

                log.info("Script success");
                // 执行 lua 脚本
                stringRedisTemplate.execute(redisScript, keys/*message_id*/, JSON.toJSONString(messageDTO)); // keys ARGV...

                log.info("成功将消息存入Redis");
            }
        }
        return JsonResponse.success("m");
    }

    /**
     * 登录过后进行消息拉取操作
     */
    @RequestMapping("test/pullmessage")
    @IgnoreLogin
    public JsonResponse pullMessage() {
        // 这里 按照 上面步骤开始 id=1 连接 然后 1->2 发送消息，此时2 离线 存入redis
        // 现在 2 开始连接 过后 需要 向redis中获取数据
        Long id = 2L;
        ImmutableList<String> keys = ImmutableList.of(StringUtils.join("message_", id));
        String luaScript = LuaScript.pullMessageScript();
        RedisScript<List> redisScript = new DefaultRedisScript<>(luaScript, List.class);
        log.info("ready pull message");
        // 执行
        List<MessageDTO> ans = stringRedisTemplate.execute(redisScript, keys);
        System.out.println(ans);

//        return JsonResponse.success(JSON.toJSONString(ans.stream().map(a -> JSON.parse(a)).collect(Collectors.toList())));
//        return JsonResponse.success("1");
        return JsonResponse.success(ans);
    }

    @Autowired
    private MessageService messageService;

    @RequestMapping("test/sqlmessage")
    @IgnoreLogin
    public JsonResponse sqlMessage() {
//        messageService.updateByIDAndSend(1L);
//        for (int i = 0; i < 5; i++) {
//            System.out.println(SHA256.getSHA256StrJava("1234"));
//        }
        Message message = new Message(1L, 2L, "flower like flower");
        messageService.addMessage(message);
        return JsonResponse.success(messageService.findMessagesBySendId(1L));
//        return JsonResponse.success(messageService.findMessageByUserId(1L));
//        return JsonResponse.success(messageService.findMessageByPullId(2L));

    }

    @Autowired
    private UserService userService;

    @RequestMapping("test/register")
    @IgnoreLogin
    public JsonResponse sqlUser() {
        String username = "HOSHINO";
        String password = SHA256.getSHA256StrJava("TAKANASHI");
        User user = new User(username, password);
        userService.registerUser(user);
        return JsonResponse.success("1");
    }

    @RequestMapping("test/getuser")
    @IgnoreLogin
    public JsonResponse getUser() {
        String username = "HOSHINO";
        User user = userService.getUserByUserName(username);
        return JsonResponse.success(user.getPassword().equals(SHA256.getSHA256StrJava("TAKANASHI")));
    }

    @Autowired
    private BlogMapper blogMapper;

    @RequestMapping("test/getcollection/blogcomment")
    @IgnoreLogin
    public JsonResponse getCollectionBlog() {
        List<Blog> blogList = blogMapper.findBlogsByUser(1L);
        System.out.println(blogList);
        return JsonResponse.success(blogList);
    }

    @Autowired
    private CommentMapper commentMapper;

    @RequestMapping("test/comment/getTree")
    @IgnoreLogin
    public JsonResponse getCommentTree() {
        List<Comment> list = commentMapper.getTreeComment(1L);

        return JsonResponse.success(list);
    }

    @Autowired
    private CollectionBlogMapper collectionBlogMapper;

    @RequestMapping("test/collectionBlog/findTree")
    @IgnoreLogin
    public JsonResponse findCollectionBlogTree() {
        CollectionBlog collectionBlog = new CollectionBlog();
        collectionBlog.setId(3L);
        return JsonResponse.success(collectionBlogMapper.findTreeNode(collectionBlog));
    }

    @RequestMapping("test/collectionBlog/findUser")
    @IgnoreLogin
    public JsonResponse findCollectionBlogByUser() {
        CollectionBlog collectionBlog = new CollectionBlog();
        collectionBlog.setUserId(1L);
//        System.out.println();
        return JsonResponse.success(collectionBlogMapper.findAllByUserId(collectionBlog));
    }

    @Autowired
    private FileService fileService;

    @RequestMapping("/uploadFile")
    @IgnoreLogin
    public void ss(MultipartFile file) {
        try {
            Map<String, String> map = fileService.upload(file);
            System.out.println(map.get("url"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @RequestMapping("test/getALLUserDetails")
    @IgnoreLogin
    public JsonResponse UserDetailsList() {
        return JsonResponse.success(userService.getFocusAndUserDetails(1L));
    }

    @Autowired
    private BlogTagMapper blogTagMapper;

    @RequestMapping("test/addBlogTag")
    @IgnoreLogin
    public JsonResponse addBlogTag(@RequestBody TagDTO tagDTO) {
        Long bid = tagDTO.getBlog_id();
        List<Long> ids = tagDTO.getTag_ids();
        if (bid != null && ids != null) {
            blogTagMapper.addListBlogTag(bid, ids);
        }
        return JsonResponse.success(1);
    }

    @Autowired
    private Trie trie;

    @RequestMapping("test/Trie")
    @IgnoreLogin
    public JsonResponse testTrie() {
        return JsonResponse.success(trie.sensitiveWordReplace("敏感敏感词"));
    }

    @Autowired
    private SubscribeMapper subscribeMapper;

    @RequestMapping("test/subscribe/getList")
    public JsonResponse testSubscribeGetList(HttpServletRequest request) {
        Long uid = (Long) request.getAttribute("USER_ID");
        List<Subscribe> sl = subscribeMapper.getUserSubscribeCollection(uid);
        Collections.sort(sl, (a, b) -> {
            if (a.getCreateTime().after(b.getCreateTime())) {
                return -1;
            } else {
                return 1;
            }
        });
        return JsonResponse.success(sl);
    }
}

